home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_12_09 / single / mobject.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-29  |  12.9 KB  |  383 lines

  1. //  Listing 4
  2. //  mobject.cpp
  3. //
  4. //  Copyright Singleton Systems Ltd 1994 
  5.  
  6. #include    "stdafx.h" 
  7. #include    <new.h>
  8. #include    "farheapb.h"
  9. #include    "mobject.h"
  10. #include    <iomanip.h>
  11. #include    "newtest.h"
  12.  
  13. // ... debugging code not shown here 
  14. //     due to space constraints ...
  15.  
  16. void FAR * MemoryObject::operator new (size_t size) 
  17. // standard operator new, used for derived classes.
  18.     {return new (size) MemoryObject;}
  19.  
  20. void FAR * MemoryObject::operator new 
  21.                     (size_t /*std_size */, size_t size)
  22. //  Extended operator new, used by AllocateBlock and 
  23. //  standard operator new
  24. {
  25. FP_FHB allocated_block;
  26. FP_MOBJECT first_fit = FindFreeSpace (size, 
  27.                                       allocated_block);
  28. if (first_fit == NULL) 
  29.     {   
  30.     //  Unable to satisfy request, raise memory 
  31.     //  exception
  32.     _PNH handler = _set_new_handler (0);    
  33.     //  Get current new handler and restore it
  34.     _set_new_handler (handler);
  35.     (* handler) (size);         //  call the handler 
  36.     // Fail regardless of value returned by the handler
  37.     return NULL;                 
  38.     }
  39.  
  40. __segment cur_seg = (__segment) SELECTOROF (first_fit);
  41.  
  42. //  We now have a pointer to a free object which 
  43. //  satisfies our request.  We need to split it so 
  44. //  that we get the amount we want, and the rest 
  45. //  stays in the free list   
  46. ASSERT (AfxIsValidAddress (first_fit, 
  47.                            sizeof (MemoryObject)));
  48. ASSERT (first_fit->flags == unallocated);
  49. unsigned int total_block_size = size; 
  50. //  Allocate in units of DWORDs
  51. total_block_size = ((total_block_size + 3) >> 2) << 2;
  52. if (first_fit->mo_block_size < 
  53.     total_block_size + sizeof (MemoryObject))
  54.     {   
  55.     //  We need to have space for this block plus at 
  56.     //  least another MemoryObject.  Not enough space 
  57.     //  to split the block, so do not, just unchain
  58.     //  from free list
  59.     if (first_fit->prev_mo != NULL)
  60.         (cur_seg:>first_fit->prev_mo)->next_mo = 
  61.                                 first_fit->next_mo;
  62.     else    
  63.         //  This is the first block in the free list
  64.         allocated_block->free_list = 
  65.                                 first_fit->next_mo;
  66.     if (first_fit->next_mo != NULL)
  67.         (cur_seg:>first_fit->next_mo)->prev_mo = 
  68.                                 first_fit->prev_mo;
  69.     else    //  This is the last block in the list
  70.         allocated_block->end_free_list = 
  71.                                 first_fit->prev_mo;
  72.     }
  73. else
  74.     {
  75.     FP_MOBJECT new_free = 
  76.         (FP_MOBJECT) ((DWORD) first_fit + 
  77.                        total_block_size);
  78.     //  Convert first_fit to DWORD, to increment by 
  79.     //  units of bytes rather then MemoryObjects
  80.     ASSERT (AfxIsValidAddress (new_free, 
  81.                             sizeof (MemoryObject)));
  82.     new_free->my_heap_block = first_fit->my_heap_block;
  83.     new_free->prev_mo = first_fit->prev_mo;
  84.     new_free->next_mo = first_fit->next_mo; 
  85.     new_free->mo_block_size = 
  86.         first_fit->mo_block_size - total_block_size; 
  87.     new_free->SetAllocationFlag (unallocated);
  88.     first_fit->mo_block_size = total_block_size;
  89.     if (first_fit->prev_mo != NULL)
  90.         (cur_seg:>first_fit->prev_mo)->next_mo = 
  91.                     MO_BASED_VOID_FROM_LP (new_free);
  92.     else    //  This is the first block in the list
  93.         allocated_block->free_list = 
  94.                     MO_BASED_VOID_FROM_LP (new_free);
  95.     if (first_fit->next_mo != NULL)
  96.         (cur_seg:>first_fit->next_mo)->prev_mo = 
  97.                     MO_BASED_VOID_FROM_LP (new_free);
  98.     else    //This is the last block in the list
  99.         allocated_block->end_free_list = 
  100.                     MO_BASED_VOID_FROM_LP (new_free);
  101.     }
  102.  
  103. //  We have removed the allocated block from the free 
  104. //  list, so we need to add it to the in-use list
  105. if (allocated_block->in_use_list == NULL)   
  106.     //  This is the first block to be allocated
  107.     {
  108.     allocated_block->in_use_list = 
  109.             allocated_block->end_in_use_list = 
  110.                     MO_BASED_VOID_FROM_LP (first_fit);
  111.     }
  112. else    
  113.     //  Scan through the in-use list to insert the 
  114.     //  block in address order
  115.     {
  116.     FP_MOBJECT p_mo = 
  117.                 cur_seg:>allocated_block->in_use_list;
  118.     while (OFFSETOF (p_mo) != NULL)
  119.         if (first_fit > p_mo) p_mo = 
  120.                             cur_seg:>p_mo->next_mo;
  121.         else break; 
  122.     //  Now insert first_fit before p_mo 
  123.     first_fit->next_mo = MO_BASED_VOID_FROM_LP (p_mo);
  124.     if (OFFSETOF (p_mo) == NULL)
  125.         {   
  126.         //  We have reached the end of the list, so 
  127.         //  insert here
  128.         #if defined (_DEBUG)
  129.         //  For easy display in the MSVC Debugger 
  130.         //  Locals window
  131.         FP_MOBJECT trace1 = 
  132.             cur_seg:>allocated_block->end_in_use_list;
  133.         #endif      
  134.         (cur_seg:>allocated_block->end_in_use_list)
  135.             ->next_mo 
  136.                 = MO_BASED_VOID_FROM_LP (first_fit);
  137.         first_fit->prev_mo = 
  138.                     allocated_block->end_in_use_list;
  139.         allocated_block->end_in_use_list = 
  140.                     MO_BASED_VOID_FROM_LP (first_fit);
  141.         }
  142.     else 
  143.         {
  144.         ASSERT (AfxIsValidAddress (p_mo, 
  145.                             sizeof (MemoryObject)));
  146.         first_fit->prev_mo = p_mo->prev_mo;
  147.         if (p_mo->prev_mo == NULL)      
  148.             //  This is the first block
  149.             allocated_block->in_use_list = 
  150.                     MO_BASED_VOID_FROM_LP (first_fit);
  151.         else 
  152.             (cur_seg:>p_mo->prev_mo)->next_mo = 
  153.                     MO_BASED_VOID_FROM_LP (first_fit);
  154.         p_mo->prev_mo = 
  155.                     MO_BASED_VOID_FROM_LP (first_fit);
  156.         }
  157.     }                    
  158. #if defined (_DEBUG)
  159.     first_fit->Lno = 0;
  160.     first_fit->Fname = NULL;
  161. #endif
  162. return first_fit;    
  163. }
  164.  
  165. void MemoryObject::operator delete (void FAR * p_void)
  166. {
  167. FP_MOBJECT p_mo = (FP_MOBJECT) p_void;
  168. ASSERT (AfxIsValidAddress (p_mo, 
  169.                             sizeof (MemoryObject)));
  170. FP_FHB this_block = FarHeapBlock::GetHbFromHandle 
  171.                                 (p_mo->my_heap_block);
  172. if (this_block == NULL)
  173.     {   
  174.     //  Unable to access block, raise memory exception 
  175.     //    in non-debug build
  176.     AfxThrowMemoryException();
  177.     return;
  178.     }
  179.  
  180. __segment cur_seg = (__segment) SELECTOROF (p_void);
  181.  
  182. // ... debugging code not shown here 
  183. //     due to space constraints ...
  184.  
  185. //  First, unlink this block from the in-use list
  186. if (p_mo->prev_mo != NULL)
  187.     //  Point the previous block at the next block 
  188.     (cur_seg:>p_mo->prev_mo)->next_mo = p_mo->next_mo;
  189. else    
  190.     {   
  191.     //  This is the first block in the list
  192.     //  Check that the management structures also
  193.     //  think that it is the first block in the list
  194.     ASSERT (OFFSETOF (p_mo) == 
  195.                 (WORD) (this_block->in_use_list));
  196.     //  The first block will now be the next block
  197.     this_block->in_use_list = p_mo->next_mo;
  198.     }
  199.     
  200. if (p_mo->next_mo != NULL)
  201.     //  Set the next block to point to the previous 
  202.     //    block
  203.     (cur_seg:>p_mo->next_mo)->prev_mo = p_mo->prev_mo;
  204. else
  205.     {   
  206.     //  This is the last block in the list
  207.     //  Check that the management structures also
  208.     //  think that it is the last block in the list
  209.     ASSERT (OFFSETOF (p_mo) == 
  210.             (WORD) (this_block->end_in_use_list));
  211.     this_block->end_in_use_list = p_mo->prev_mo;
  212.     }
  213.     
  214. //  Now chain the block back into the list of free 
  215. //    blocks, 
  216. if (this_block->free_list == NULL)
  217.     {   
  218.     //  The free list is currently empty
  219.     //  Check that the management structures also
  220.     //  think that it is free
  221.     ASSERT (this_block->end_free_list == NULL);
  222.     this_block->free_list = 
  223.                 this_block->end_free_list =
  224.                     MO_BASED_VOID_FROM_LP (p_mo);
  225.     p_mo->next_mo = p_mo->prev_mo = NULL;
  226.     }
  227. else
  228.     {
  229.     FP_MOBJECT insert_point = 
  230.                     cur_seg:>this_block->free_list;
  231.     //  Starting at the beginning, scan through 
  232.     //  the free list to find the insertion point.  
  233.     //  Insert in memory order
  234.     while (OFFSETOF (insert_point) != NULL && 
  235.                      insert_point < p_mo)
  236.         insert_point = cur_seg:>insert_point->next_mo;
  237.                          
  238.     if (OFFSETOF (insert_point) == NULL)
  239.         {   //  insert at the end of the list
  240.         ASSERT ((cur_seg:>this_block->end_free_list)
  241.                                     ->next_mo == NULL);
  242.         (cur_seg:>this_block->end_free_list)->next_mo 
  243.                         = MO_BASED_VOID_FROM_LP (p_mo);
  244.         p_mo->prev_mo = this_block->end_free_list;
  245.         p_mo->next_mo = NULL;
  246.         this_block->end_free_list = 
  247.                         MO_BASED_VOID_FROM_LP (p_mo);
  248.         } 
  249.     else
  250.         {   
  251.         //  Insert the block before insert_point
  252.         ASSERT (AfxIsValidAddress (insert_point, 
  253.                             sizeof (MemoryObject)));
  254.         ASSERT (AfxIsValidAddress (p_mo, 
  255.                             sizeof (MemoryObject)));
  256.         p_mo->next_mo = 
  257.                 MO_BASED_VOID_FROM_LP (insert_point);
  258.         p_mo->prev_mo = insert_point->prev_mo;
  259.         if (insert_point->prev_mo == NULL)
  260.             {   
  261.             //  p_mo to be the new first free block
  262.             ASSERT (insert_point == 
  263.                     cur_seg:>this_block->free_list);
  264.             this_block->free_list = 
  265.                         MO_BASED_VOID_FROM_LP (p_mo);
  266.             }                            
  267.         else
  268.             (cur_seg:>insert_point->prev_mo)->next_mo 
  269.                         = MO_BASED_VOID_FROM_LP (p_mo);
  270.         insert_point->prev_mo = 
  271.                         MO_BASED_VOID_FROM_LP (p_mo);
  272.         }
  273.     }
  274.  
  275. //  Now see whether it is possible to compact the 
  276. //  inserted block with either (or both) of the 
  277. //  adjacent blocks.  First, can we combine it with 
  278. //  the previous block?
  279. if (p_mo->prev_mo != NULL)
  280.     {
  281.     if ((DWORD) p_mo == (DWORD)(cur_seg:>p_mo->prev_mo)
  282.             + (cur_seg:>p_mo->prev_mo)->mo_block_size)
  283.         {   //  Compact with the previous block
  284.         (cur_seg:>p_mo->prev_mo)->next_mo = 
  285.                                         p_mo->next_mo;
  286.         if (p_mo->next_mo == NULL)
  287.             {   //  This was the last block in the list
  288.             ASSERT (cur_seg:>this_block->end_free_list
  289.                     == p_mo);
  290.             this_block->end_free_list = p_mo->prev_mo;
  291.             }
  292.         else
  293.             (cur_seg:>p_mo->next_mo)->prev_mo = 
  294.                                 p_mo->prev_mo;
  295.         (cur_seg:>p_mo->prev_mo)->mo_block_size += 
  296.                                 p_mo->mo_block_size;
  297.         //  Finally, as the block has been combined 
  298.         //  with the one before, set the pointer to 
  299.         //  that block
  300.         p_mo = cur_seg:>p_mo->prev_mo;
  301.         } 
  302.     } 
  303. //  Can we combine it with the next block
  304. if (p_mo->next_mo != NULL)
  305.     {
  306.     if ((DWORD) p_mo + p_mo->mo_block_size == 
  307.                     (DWORD) (cur_seg:>p_mo->next_mo))
  308.         {   //  Compact with the next block 
  309.         p_mo->mo_block_size += 
  310.             (cur_seg:>p_mo->next_mo)->mo_block_size;
  311.         if ((cur_seg:>p_mo->next_mo)->next_mo == NULL)
  312.             {   
  313.             //  Next block is the last block in list
  314.             ASSERT (this_block->end_free_list == 
  315.                     p_mo->next_mo);
  316.             this_block->end_free_list = 
  317.                  MO_BASED_VOID_FROM_LP (p_mo);
  318.             }                                     
  319.         else
  320.             (cur_seg:>(cur_seg:>p_mo->next_mo)
  321.                         ->next_mo)->prev_mo =
  322.                  MO_BASED_VOID_FROM_LP (p_mo);
  323.         p_mo->next_mo = 
  324.                 (cur_seg:>p_mo->next_mo)->next_mo;
  325.         }
  326.     }
  327.  
  328. //  Finally, see if the FarHeapBlock is empty.  
  329. //  If so, return it to Windows
  330. if (this_block->in_use_list == NULL)
  331.     {   //  The block is empty, return it to Windows
  332.     ASSERT (this_block->end_in_use_list == NULL);
  333.     delete this_block;
  334.     }
  335. }
  336.  
  337. MemoryObject::MemoryObject ()
  338. {
  339. #if defined (_DEBUG)
  340.     flags = allocated;
  341.     _fstrcpy (validity_tag, validity_tag_value);
  342. #endif
  343. }
  344.  
  345. MemoryObject::~MemoryObject ()
  346. {
  347. #if defined (_DEBUG)
  348.     if (_fstrcmp (validity_tag, validity_tag_value) 
  349.         != 0)
  350.         {
  351.         TRACE0 ("MemoryObject::~MemoryObject() "
  352.                 "attempting to delete an object with "
  353.                 "an invalid tag!\n");
  354.         ASSERT (FALSE);
  355.         }
  356.     flags = unallocated;
  357. #endif
  358. }
  359.  
  360. inline FP_MOBJECT MemoryObject::FindFreeSpace 
  361.         (size_t size, FP_FHB & block_allocated)
  362. {
  363. //  As this routine is only called once, from 
  364. //  MemoryObject::new, it is declared as 'inline' for 
  365. //  efficiency and speed
  366.  
  367. //  First check that the requested size is within 
  368. //  limits.  We cannot allocate a block that is bigger
  369. //  that a FarHeapBlock less overheads.
  370. ASSERT (block_allocated->DefaultSize () > 
  371.         sizeof (FarHeapBlock) + sizeof(MemoryObject));
  372. if (size + sizeof (FarHeapBlock) + 
  373.     sizeof (MemoryObject) > block_allocated->DefaultSize ())
  374.     {
  375.     TRACE ("MemoryObject::FindFreeSpace cannot "
  376.            "allocate requested space\n");
  377.     ASSERT (FALSE);
  378.     return NULL;
  379.     }
  380.          
  381. // ... code not shown here 
  382. //     due to space constraints ...
  383.